#pragma once
#include <cstdarg>
#include <sfse_common/Errors.h>

#include "ScaleformAPI.h"
#include "ScaleformGFxEvent.h"
#include "ScaleformGFxLog.h"
//#include "ScaleformGFxState.h"
#include "ScaleformGFxTypes.h"
//#include "sfse/ScaleformValue.h"
//#include "ScaleformRefCountBase.h"
#include "ScaleformStat.h"
#include "sfse_common/Types.h"
#include "sfse/ScaleformState.h"


namespace Scaleform
{
    class AmpMovieObjectDesc;

    namespace GFx
    {
        //class FunctionHandler;

class Value;
        class StateBagImpl
        {
        };

        enum PlayState
        {
            State_Playing,
            State_Stopped
        };

        class EventID;
        class MovieImpl;

        namespace AS3
        {
            class Stage
            {
            };

            class MovieDefRootNode
            {
            };

            class MovieRoot // 0x4E8
            {
            public:
                virtual ~MovieRoot();

                virtual void Unk_01();
                virtual void Unk_02();
                virtual void Unk_03();
                virtual void Unk_04();
                virtual void Unk_05();
                virtual void Unk_06();
                virtual void Unk_07();
                virtual void Unk_08();
                virtual void Unk_09(); // ForceCollect(uint)
                virtual void Unk_0A();
                virtual void Unk_0B(); // SuspendGC(bool)
                virtual void Unk_0C(); // ScheduleGC(int)
                virtual void Unk_0D();
                virtual void Unk_0E();
                virtual void Unk_0F();
                virtual void Unk_10();
                virtual void Unk_11();
                virtual void Unk_12();
                virtual void Unk_13();
                virtual void Unk_14();
                virtual void Unk_15();
                virtual void Unk_16();
                virtual void Unk_17();
                virtual void Unk_18();
                virtual void Unk_19();
                virtual void Unk_1A();
                virtual void Unk_1B();
                virtual void Unk_1C();
                virtual void Unk_1D();
                virtual void Unk_1E();
                virtual void Unk_1F();
                virtual void Unk_20();
                virtual void Unk_21();
                virtual void Unk_22();
                virtual void Unk_23();
                virtual void Unk_24();
                virtual void Unk_25();
                virtual void Unk_26();
                virtual void Unk_27();
                virtual void Unk_28();
                virtual void Unk_29();
                virtual void Unk_2A();
                virtual void Unk_2B();
                virtual void CreateString(Value* pValue, const char* pString);
                virtual void CreateStringW(Value* pValue, const wchar_t* pString);
                virtual void CreateObject(Value* pValue, const char* className = NULL, const Value* pArgs = NULL,
                                          u32 nArgs = 0);
                virtual void CreateArray(Value* pValue);
                virtual void CreateFunction(Value* pValue, void* pFunc, void* puserData = NULL); // FunctionHandler
                virtual bool SetVariable(const char* pVarPath, const Value* value, u32 setType = 0);
                virtual bool GetVariable(Value* pValue, const char* pVarPath) const;
                virtual void Unk_33();
                virtual void SetVariableArraySize(const char* pPathToVar, u32 size, u32 setType = 0);
                virtual u32 GetVariableArraySize(const char* pPathToVar);
                virtual bool GetVariableArray(u32 type, const char* pPathToVar, u32 index, void* pData,
                                              u32 count);
                virtual bool IsAvailable(const char* pPathToMethod);
                virtual bool Invoke(const char* pPathToMethod, Value* pResult, const Value* pArgs, u32 nArgs);
                virtual bool Invoke(const char* pPathToMethod, Value* pResult, const char* pArgFmt, ...);
                virtual bool InvokeArgs(const char* pPathToMethod, Value* presult, const char* pArgFmt,
                                        va_list args);
                virtual void GetMemoryContext();
                virtual void GetStringManager();
                virtual void GetTextAllocator();
                virtual void BroadcastGeolocationStatusEvent(const EventID* eventID);

                /* =unk37()
                 
                bool Invoke(const char* pPathToMethod, Value* presult, const char* pArgFmt, ...)
                {
                    // Delegate to InvokeArgs
                    va_list args;
                    va_start(args, pArgFmt);
                    bool retVal = InvokeArgs(pPathToMethod, presult, pArgFmt, args);
                    va_end(args);
                    return retVal;
                }*/
            };
        }

        class MovieDef
        {
        };

        class MovieDefImpl : public MovieDef
        {
        };

        class Movie : public RefCountBase<Movie>, public StateBag
        {
        public:
            enum AlignType
            {
                Align_Center,
                Align_TopCenter,
                Align_BottomCenter,
                Align_CenterLeft,
                Align_CenterRight,
                Align_TopLeft,
                Align_TopRight,
                Align_BottomLeft,
                Align_BottomRight
            };

            enum HE_ReturnValueType
            {
                HE_NotHandled = 0,
                HE_Handled = 1,
                HE_NoDefaultAction = 2,
                HE_Completed = (HE_Handled | HE_NoDefaultAction)
            };

            enum HitTestType
            {
                HitTest_Bounds = 0,
                HitTest_Shapes = 1,
                HitTest_ButtonEvents = 2,
                HitTest_ShapesNoInvisible = 3
            };

            enum GCFlags
            {
                GCF_Quick = 0,
                GCF_Medium = 1,
                GCF_Full = 2
            };

            enum ReportFlags
            {
                Report_ShortFileNames = 0x0001,
                Report_NoCircularReferences = 0x0002,
                Report_SuppressOverallStats = 0x0004,
                Report_AddressesForAnonymObjsOnly = 0x0008,
                Report_SuppressMovieDefsStats = 0x0010,
                Report_NoEllipsis = 0x0020
            };

            enum ScaleModeType
            {
                SM_NoScale,
                SM_ShowAll,
                SM_ExactFit,
                SM_NoBorder
            };

            enum SetArrayType
            {
                SA_Int,
                SA_Double,
                SA_Float,
                SA_String,
                SA_StringW,
                SA_Value
            };

            enum SetVarType
            {
                SV_Normal,
                SV_Sticky,
                SV_Permanent
            };

            virtual ~Movie();

            virtual MovieDef* GetMovieDef();
            virtual u32 GetCurrentFrame();
            virtual bool HasLooped();
            virtual void GotoFrame(u32 frameNumber);
            virtual bool GotoLabeledFrame(const char* plabel, s32 offset = 0);
            virtual void SetPlayState(PlayState s);
            virtual PlayState GetPlayState();
            virtual bool IsValid();
            virtual void SetVisible(bool visible);
            virtual bool GetVisible();
            virtual u64 GetASTimerMs();
            virtual void SetViewport(const Viewport& viewDesc);
            virtual void GetViewport(Viewport* pviewDesc);
            virtual void SetViewScaleMode(ScaleModeType scaleMode);
            virtual ScaleModeType GetViewScaleMode();
            virtual void SetViewAlignment(AlignType alignType);
            virtual AlignType GetViewAlignment();
            virtual Render::RectF GetVisibleFrameRect();
            virtual Render::RectF GetSafeRect();
            virtual void SetSafeRect(const Render::RectF& rect);
            virtual void SetEdgeAAMode(Render::EdgeAAMode edgeAA);
            virtual Render::EdgeAAMode GetEdgeAAMode();
            virtual void Restart(bool advance0 = true);
            virtual float Advance(float deltaT, u32 frameCatchUpCount = 2, bool capture = true);
            virtual void Capture(bool onChangeOnly = true);
            virtual const ContextImpl::MovieDisplayHandle& GetDisplayHandle();
            virtual void SetCaptureThread(ThreadId captureThreadId);
            virtual void ShutdownRendering(bool wait);
            virtual bool IsShutdownRenderingComplete();
            virtual void SetPause(bool pause);
            virtual bool IsPaused();
            virtual void SetBackgroundColor(const Render::Color BgColor);
            virtual void SetBackgroundAlpha(float alpha);
            virtual float GetBackgroundAlpha();
            virtual u32 HandleEvent(const Event& event);
            virtual void GetMouseState(u32 mouseIndex, float* x, float* y, u32* buttons);
            virtual void NotifyMouseState(float x, float y, u32 buttons, unsigned mouseIndex = 0);
            virtual bool HitTest(float x, float y, HitTestType testCond = HitTest_Shapes, unsigned controllerIdx = 0);
            virtual void* GetUserData() const;
            virtual void SetUserData(void* pData);
            virtual bool IsMovieFocused() const;
            virtual bool GetDirtyFlag(bool doReset = true);
            virtual void SetMouseCursorCount(u32 n);
            virtual u32 GetMouseCursorCount() const;
            virtual void SetControllerCount(u32 n);
            virtual u32 GetControllerCount() const;
            virtual void GetStats(StatBag* pbag, bool reset = true);
            virtual MemoryHeap* GetHeap() const;
            virtual void ForceCollectGarbage(u32 gcFlags = GCF_Full);
            virtual void SuspendGC(bool suspend);
            virtual void ScheduleGC(u32 gcFlags = GCF_Full);
            virtual void PrintObjectsReport(UInt32 flags = 0, Log* log = NULL, const char* swfName = NULL, Ptr<AmpMovieObjectDesc>* root = NULL, MemoryHeap* heap = NULL);
            virtual Render::RectF TranslateToScreen(const Render::RectF& p, Render::Matrix2F* puserMatrix = 0);
            virtual Render::PointF TranslateToScreen(const Render::PointF& p, Render::Matrix2F* puserMatrix = 0);
            virtual bool TranslateLocalToScreen(const char* pathToCharacter, const Render::PointF& pt, Render::PointF* presPt, Render::Matrix2F* userMatrix = 0);
            virtual bool SetControllerFocusGroup(u32 controllerIdx, u32 focusGroupIndex);
            virtual u8 GetControllerFocusGroup(u32 controllerIdx) const;
            virtual void ResetInputFocus(unsigned controllerIdx);
            virtual bool IsExitRequested() const;
            virtual void GetViewMatrix3D(Render::Matrix3F* m);
            virtual void SetViewMatrix3D(const Render::Matrix3F& m);
            virtual void GetProjectionMatrix3D(Render::Matrix4F* m);
            virtual void SetProjectionMatrix3D(const Render::Matrix4F& m);
            virtual void SetStageAutoOrients(bool v = true);
            virtual void ForceUpdateImages();
            virtual void MakeAreaVisible(const Render::RectF& screenRect, const Render::RectF& box, UInt32 flags = 0);
            virtual void RestoreViewport();

            AS3::MovieRoot* movieRoot; // 18
            //...
        };

        // 0x3170 
        class MovieImpl : public Movie 
        {
        public:
            virtual void SetVerboseAction(bool verboseAction);
            virtual void SetActionErrorsSuppress(bool action);
            virtual bool AcceptAnimMovesWith3D() const;
        };
    }
}
